#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>



//int main()
//{
//    unsigned char i = 0;
//    //unsigned char 的取值范围是 0 ~ 255
//    //会死循环，一直打印hello world
//
//    for (i = 0; i <= 255; i++)
//    {
//        printf("hello world\n");
//    }
//
//    return 0;
//}


//#include <stdio.h>
//#include <windows.h>
//
//int main()
//{
//    unsigned int i;// 无符号整型，则i一定是>=0的
//    for (i = 9; i >= 0; i--)
//    {
//        printf("%u\n", i);
//        i是无符号整型，占32个字节
//        Sleep(1000);
//    }
//    return 0;
//}


//X86环境，小端字节序
//
//int main()
//{
//	int a[4] = { 1, 2, 3, 4 };
//	int* ptr1 = (int*)(&a + 1);
//	int* ptr2 = (int*)((int)a + 1);
//	printf("%x\n", ptr1[-1]); 
//	//ptr1[-1] == *(ptr1 - 1) -- 4
//	printf("%x\n", *ptr2);
//	//在ptr2中，a首先被强制转化成了int类型，整型类型+1就是+1
//	//例如，a如果是0x001244ff40, 被强制类型转化成整型之后，+1就是0x0012ff41
//	//所以是向后加了一个字节的大小，然后重新强制类型转化成int*类型的指针赋给ptr2
//	//因为是小端存储，所以应该是这样存储的
//	//01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00
////未操作a的地址是指向01位置
////操作后a的地址是指向01后一个00这个字节的位置
//	//整形指针类型解引用访问4个字节
//	//ptr2解引用，是解引用00 00 00 02这四个字节
//	//小端存储，所以解引用后的结果是0x02 00 00 00
//	return 0;
//}


//*****************************************************************//


//浮点数在内存中的存储
//浮点数表示的范围在float.h中表示，整数的取值范围为在limits.h中表示

//int main()
//{
//	int n = 9;
//	float* pFloat = (float*)&n;
//	printf("n的值为%d\n", n);
//	printf("*pFloat的值为%f\n", *pFloat);
//
//	*pFloat = 9.0;
//	printf("num的值为%d\n", n);
//	printf("*pFloat的值为%f\n", *pFloat);
//
//	return 0;
//}
//float* 类型解引用会解引用4个字节的空间，这4个字节的空间应该是float类型的数据
//通过上面的例子可以发现
//***************************************浮点数和整数在内存中的存储方式是不一样的****************************************************************/

//浮点数在内存中的存储
//任何一个二进制浮点数V都可以表示成
//V = (-1)^S * M * 2^ E
//(-1)表示符号位，如果S = 0，V是正数， 如果S = 1，V是负数
//M表示有效数字，M是大于1且小于2的
//2^E表示指数位

//例如，十进制的5.1，写成二进制101.1
// = (-1)^0 * 1.011 * 2 ^ 2
// 按照上面的格式，S = 0， M = 1.011 E = 2
//所以浮点数的存储秩序存储S，M，E的值


//对于32位的浮点数(float)，最高的一位存储符号位S，接着的8位存储指数E，剩下的23位存储有效数字M
//对于64位的浮点数(double)，最高的一位存储符号位S，接着的11位存储指数E，剩下的52位存储有效数字M



//浮点数存储的过程
//前面讲，M是大于等于1，小于2的形式，即M可以写成1.xxxxxxxxxxxx的形式，其中xxxxxxxxx表示小数部分
//IEEE754规定，在计算机内部保存的时候，默认这个数的第一位总是1，因此就可以舍去，只保存后面的xxxx部分。
//比如，保存1.01的时候，就只保存01，等到读取的时候，直接在小数点前面加上第一位的1，这样做的目的是
//节省一位有效数字
//以32位浮点数（float）为例，留给M只有23位，如果将第一位的1舍去，等于可以保存24位有效数字


//指数E较为复杂
//首先，指数E是一个无符号正数（unsigned char）
//如果E是8位，它的取值范围是0~255，如果E是11位，它的取值范围是0~2047,但是，科学计数法中
//E是可以出现负数的，所以为了解决这个问题，IEEE 754规定
//存入内存中，E的真实值必须再加上一个中间数
//对于8位的E，这个中间数是127，对于11位的E，这个中间数是1023
//比如，2^10的E是10，保存成为32位的浮点数的时候，必须保存位10 + 127 = 137 即 10001001

//举例

//int main()
//{
//	float f = 5.5f;
//	//十进制： 5.5
//	//二进制： 101.1
//	//1.011 * 2 ^ 2
//	//(-1) ^ 0 * 1.011 * 2 ^ 2
//	//S = 0
//	//E = 2 + 127 = 129
//	//M = 1.011
//	//0 10000001 01100000000000000000000
//	//二进制
//	//0100 0000 1011 0000 0000 0000 0000 0000
//	//十六进制
//	//40 B0 00 00
//	//小端存储
//	return 0;
//}


//int main()
//{
//	float f = 6.25;
//
//	//十进制 6.25
//	//二进制 0110.01
//	//(-1) ^ 0 * 1.1001 * 2 ^ 2
//	//S = 0
//	//E = 2 + 127 = 129
//	//M = 1.1001
//	//0 10000001 10010000000000000000000
//	//二进制理解
//	//0100 00000 1100 1000 0000 0000 0000 0000
//	//十六进制
//	//40 C8 00 00
//	//小端存储
//	
//	return 0;
//}

//但举例的时候，不要举一些极端的例子，无法讲十进制精准转换成二进制的数字
//int main()
//{
//	float f = 0.545f;
//	printf("%.10f\n", f);
//	return 0;
//}
// 

//指数E从内存中取出还可以再分成三种情况
// 1.E不全为0或不全为1的时候
// 这是，浮点数就正常倒回去计算，用E - 127（或1023）得到E的真实值，再将有效数字M加前加上第一位的1


// 2.E为全0
// 进行推算的话 真实的E的值 + 127 = 0 真实的E的值是-127，2^-127是一个非常非常小的数字
// 所以 
//这时规定
//浮点数的指数E等于 1 - 127 (或者 1 - 1023)即为真实值，有效数字M不再加上第一位的1。
//这样做是为了表示+-0，以及无限接近于0的非常小的数字

// 3.E为全1
// E为全1的时候，如果有效数字M全为0，则表示无穷大（正负还是取决于符号位S）

//再回头看最开始的例子


//int main()
//{
//	int n = 9;
//	float* pFloat = (float*)&n;
//	printf("n的值为：%d\n", n);
//	//n的类型是int类型存储
//	//二进制
//	//00000000 00000000 00000000 00001001
//	//原反补都相同，打印以%d形式打印就是9
//	printf("*pFloat的值为：%f", *pFloat);
//	//00000000 00000000 00000000 00001001，当他强制类型转换成float的时候
//	//就会被以浮点数的形式理解
//	//0 00000000 0000000 00000000 0000100
//	//此时S为0，E为全0，M为0000000 00000000 00001
//  // V = (-1) ^ 0 * 0.0000000 00000000 00001 * 2 ^ (-126) = 1.001 * 2 ^ (-146) 是一个及其接近零的正数
//	//E为全零，用来表示接近于0的非常小的数字，又是以%f的形式打印，显示六位是，所以是0.000000
//	
//	return 0;
//}


int main()
{
	int n = 9;
	float* pFloat = (float*)&n;

	*pFloat = 9.0;
	//9.0是浮点数，以浮点数的形式存储
	//9转换成二进制是1001
	//可以写成(-1) ^ 0 * 1.001 * 2 ^ 3
	// E = 3 转化的时候应该+127 = 130
	//0 1000 0010 00100000000000000000000
	//%d打印的时候会把上面这段二进制当作整数
	//0100 0001 0001 0000 0000 0000 0000 0000 
	//最高位是符号位是0，正数，原反补都相同
	//  二进制                          -   十进制
	// 1000001000100000000000000000000 - 1091567616
	printf("n的值为：%d\n", n);

	printf("*pFloat的值为：%f\n", *pFloat);
	return 0;
}









